/*
    日志模块
*/
#pragma once
#include <iostream>
#include <string>
#include <cstdarg>
#include <ctime>
#include <fstream>
#include "lockguard.hpp"

// 日志等级
enum
{
    INFO = 0,
    DEBUG,
    WARRING,
    ERROR,
    FATAL
};

//将日志等级转换成对应字符串
const char* log_to_string[] = {"INFO", "DEBUG", "WARNING", "ERROR", "FATAL"};

const char* const logfilename = "log.txt";

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 定义一把锁，保护显示器资源

bool is_save = false;

//定义两个使能按钮
#define EnableScreen()   \
    do                   \
    {                    \
        is_save = false; \
    } while (0)

#define EnableFile()    \
    do                  \
    {                   \
        is_save = true; \
    } while (0)

#define LOG(level, format, ...)                                       \
    do                                                                \
    {                                                                 \
        logMessage(level, __FILE__, __func__, format, ##__VA_ARGS__); \
    } while (0)

std::string getTimeStr()
{
    time_t t = time(nullptr);
    std::string ret = ctime(&t);
    ret.pop_back();
    return ret;
}

void saveToFile(const std::string& filename, const std::string& msg)
{
    std::ofstream out(filename, std::ios::app);
    if(!out.is_open())
    {
        std::cout << "日志文件打开失败\n";
        return;
    }
    out << msg;
    out.close();
}

void logMessage(int level, const std::string& filename, const std::string& funcname, const char* format, ...)
{
    // 提取可变参数
    va_list al; // 定义可变参数列表指针
    va_start(al, format); //初始化指针，让其指向给定参数的最右边一个，方便找可变参数
    char buf[1024];
    vsprintf(buf, format, al); //自动根据format格式，将可变参数填充并输出到buf中

    // 构造日志
    std::string msg = "[" + getTimeStr() + "]" /*当前时间*/
          + "[" + log_to_string[level] + "]" /*等级*/
          + "[" + filename + "]" /*文件名*/
          + "[" + "function:" + funcname + "]" /*函数名*/
          + ": " + buf; /*可变参数部分*/

    if(is_save)
    {
        // 保存到日志文件
        saveToFile(logfilename, msg);
    }
    else
    {
        // 输出到显示器
        LockGuard lock(mutex);
        std::cout << msg;
    }
}